//
// Created by wangwanlong on 2024/6/23.
//

#ifndef MCGPP_METRICS_H
#define MCGPP_METRICS_H

#include "typedef.h"
#include "graph.h"

namespace mcgpp {
  //目标函数值
  struct Metrics {
    static constexpr ll bits = 1e10;//保留10位
    Metrics() : cut_weight(0), cut_num(0), volume_weight(0), volume_num(0),volume_t_weight(0),
                conductance(std::numeric_limits<ll>::max()) {
    }
    void reset() {
      cut_weight = 0;
      cut_num = 0;
      volume_weight = 0;
      volume_num = 0;
      volume_t_weight = 0;
      conductance = std::numeric_limits<ll>::max();
    }
    // 重载 <= 运算符
    bool operator<=(const Metrics& other) const {
      return this->conductance <= other.conductance;
    }
    // 重载 < 运算符
    bool operator<(const Metrics& other) const {
      return this->conductance < other.conductance;
    }
    // 重载 == 运算符
    bool operator ==(const Metrics& other) const {
      return this->conductance == other.conductance;
    }
    // 通常，当重载 == 时，也应该重载 != 运算符
    bool operator!=(const Metrics& other) const {
      return !(*this == other);
    }

    ll calCond() {
      switch (Context::instance().objMetric) {
        case ObjMetric::cut_num :
          conductance = (static_cast<double>(cut_num) / static_cast<double>(volume_num)) * bits;
          break;
        case ObjMetric::cut_weight :
          conductance = (static_cast<double>(cut_weight) / static_cast<double>(volume_weight)) * bits;
          break;
        case ObjMetric::real:
          conductance = (static_cast<double>(cut_weight) / static_cast<double>(volume_t_weight)) * bits;
          break;
        default:
          ERROREXIT("obj error!");
      }
      return conductance;
    }
    IDType cut_weight;
    IDType cut_num;
    IDType volume_weight;
    IDType volume_num;
    IDType volume_t_weight;
    ll conductance;//电导 保留10位
  };

  namespace metrics {
    //计算图的电导
    static inline double conductance(ds::GenericGraph &g) {
      Metrics m;
      for (int i = 0; i < g._num_edges; ++i) {
        if (g.edgeIsEnabled(i) && g._connectivity_sets[i].bit() == 3){
          m.cut_weight += g.edge(i).weight();
          m.cut_num += 1;
        }
      }
      m.volume_num = std::min(g._part_info[0].num, g._part_info[1].num);
      m.volume_weight = std::min(g._part_info[0].weight, g._part_info[1].weight);
      m.volume_t_weight = std::min(g._part_info[0].t_weight, g._part_info[1].t_weight);
      m.calCond();
      return static_cast<double>(m.calCond())/1e10;
    }

    static inline void conductance(ds::GenericGraph &g, Metrics &m) {
      m.reset();
      for (int i = 0; i < g._num_edges; ++i) {
        if (g.edgeIsEnabled(i) && g._connectivity_sets[i].bit() == 3) {
          m.cut_weight += g.edge(i).weight();
          m.cut_num += 1;
        }
      }
      m.volume_num = std::min(g._part_info[0].num, g._part_info[1].num);
      m.volume_weight = std::min(g._part_info[0].weight, g._part_info[1].weight);
      m.volume_t_weight = std::min(g._part_info[0].t_weight, g._part_info[1].t_weight);
      m.calCond();
    }
  }
}
#endif //MCGPP_METRICS_H
